<!DOCTYPE html>
<html lang="zh">

<head>
    <title>goframe websocket</title>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
    <script src="//cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
    <style>
        .main-container {
            display: flex;
            gap: 20px;
            margin-top: 20px;
        }

        .left-panel {
            flex: 1;
            min-width: 300px;
            max-height: 80vh;
        }

        .right-panel {
            width: 300px;
        }

        #divShow {
            max-height: 70vh;
            overflow-y: auto;
        }

        .message-type-selector {
            margin-bottom: 10px;
        }

        .chat-input-group {
            margin-bottom: 15px;
        }

        .target-input {
            margin-top: 10px;
        }

        @media (max-width: 768px) {
            .main-container {
                flex-direction: column;
            }
            
            .left-panel,
            .right-panel {
                width: 100%;
                min-width: unset;
            }
            
            .right-panel {
                width: 100%;
            }
        }
    </style>
</head>

<body>
    <div class="container">
        <div class="main-container">
            <!-- 左侧消息显示区域 -->
            <div class="left-panel">
                <div class="panel panel-default">
                    <div class="panel-heading">
                        <h3 class="panel-title">消息列表</h3>
                    </div>
                    <div class="panel-body">
                        <div class="list-group" id="divShow"></div>
                    </div>
                </div>
            </div>

            <!-- 右侧操作区域 -->
            <div class="right-panel">
                <div class="panel panel-default">
                    <div class="panel-heading">
                        <h3 class="panel-title">连接管理</h3>
                    </div>
                    <div class="panel-body">
                        <div class="form-group">
                            <label for="txtUrl">WebSocket服务器地址</label>
                            <input class="form-control" id="txtUrl" value="ws://127.0.0.1:8800/socket"
                                placeholder="WebSocket服务器地址">
                        </div>
                        <button class="btn btn-primary" id="btnConnect">连接WebSocket</button>
                        <button class="btn btn-danger" id="btnDisconnect" disabled>断开连接</button>
                    </div>
                </div>

                <div class="panel panel-default">
                    <div class="panel-heading">
                        <h3 class="panel-title">用户操作</h3>
                    </div>
                    <div class="panel-body">
                        <div class="form-group">
                            <label for="txtUserId">用户ID</label>
                            <input class="form-control" id="txtUserId" placeholder="输入用户ID..." disabled>
                        </div>
                        <button class="btn btn-success" id="btnLogin" disabled>用户登录</button>
                        <button class="btn btn-info" id="btnIsApp" disabled>标记为App</button>
                    </div>
                </div>

                <div class="panel panel-default">
                    <div class="panel-heading">
                        <h3 class="panel-title">房间操作</h3>
                    </div>
                    <div class="panel-body">
                        <div class="form-group">
                            <label for="txtRoom">房间名称</label>
                            <input class="form-control" id="txtRoom" placeholder="输入房间名称..." disabled>
                        </div>
                        <button class="btn btn-warning" id="btnJoin" disabled>加入房间</button>
                        <button class="btn btn-danger" id="btnQuit" disabled>退出房间</button>
                    </div>
                </div>

                <div class="panel panel-default">
                    <div class="panel-heading">
                        <h3 class="panel-title">消息发送</h3>
                    </div>
                    <div class="panel-body">
                        <div class="message-type-selector">
                            <label>消息类型:</label>
                            <select class="form-control" id="msgType" disabled>
                                <option value="message">普通消息</option>
                                <option value="private_message">私聊消息</option>
                                <option value="room_message">房间消息</option>
                                <option value="broadcast_message">广播消息</option>
                                <option value="client_message">客户端消息</option>
                            </select>
                        </div>

                        <div class="chat-input-group">
                            <label for="txtContent">消息内容</label>
                            <textarea class="form-control" id="txtContent" rows="3" placeholder="输入要发送的内容..." disabled></textarea>
                        </div>

                        <div class="target-input" id="targetInputs" style="display: none;">
                            <div id="privateMessageTarget" style="display: none;">
                                <label for="targetUserId">目标用户ID</label>
                                <input class="form-control" id="targetUserId" placeholder="输入目标用户ID">
                            </div>
                            
                            <div id="roomMessageTarget" style="display: none;">
                                <label for="targetRoom">目标房间</label>
                                <input class="form-control" id="targetRoom" placeholder="输入目标房间名">
                            </div>
                            
                            <div id="clientMessageTarget" style="display: none;">
                                <label for="targetClientId">目标客户端ID</label>
                                <input class="form-control" id="targetClientId" placeholder="输入目标客户端ID">
                            </div>
                        </div>

                        <button class="btn btn-primary" id="btnSend" disabled>发送消息</button>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>

</html>

<script type="application/javascript">
    function showInfo(content) {
        $("<div class=\"list-group-item list-group-item-info\">" + content + "</div>").appendTo("#divShow")
    }
    function showWaring(content) {
        $("<div class=\"list-group-item list-group-item-warning\">" + content + "</div>").appendTo("#divShow")
    }
    function showSuccess(content) {
        $("<div class=\"list-group-item list-group-item-success\">" + content + "</div>").appendTo("#divShow")
    }
    function showError(content) {
        $("<div class=\"list-group-item list-group-item-danger\">" + content + "</div>").appendTo("#divShow")
    }

    $(function () {
        let ws = null;
        let pingInterval = null; // 心跳定时器
        let clientId = null; // 客户端ID

        // 检查连接状态
        function checkConnection() {
            if (!ws || ws.readyState !== WebSocket.OPEN) {
                showError("WebSocket未连接或连接已断开！");
                return false;
            }
            return true;
        }

        // 启用或禁用控件
        function toggleControls(connected) {
            if (connected) {
                $("#btnConnect").prop("disabled", true);
                $("#btnDisconnect").prop("disabled", false);
                $("#txtUserId, #txtContent, #txtRoom, #msgType").prop("disabled", false);
                $("#btnLogin, #btnIsApp, #btnJoin, #btnQuit, #btnSend").prop("disabled", false);
            } else {
                $("#btnConnect").prop("disabled", false);
                $("#btnDisconnect").prop("disabled", true);
                $("#txtUserId, #txtContent, #txtRoom, #msgType").prop("disabled", true);
                $("#btnLogin, #btnIsApp, #btnJoin, #btnQuit, #btnSend").prop("disabled", true);
            }
        }

        // 消息类型改变事件
        $("#msgType").change(function() {
            const msgType = $(this).val();
            $("#targetInputs > div").hide();
            
            switch(msgType) {
                case "private_message":
                    $("#privateMessageTarget").show();
                    $("#targetInputs").show();
                    break;
                case "room_message":
                    $("#roomMessageTarget").show();
                    $("#targetInputs").show();
                    break;
                case "client_message":
                    $("#clientMessageTarget").show();
                    $("#targetInputs").show();
                    break;
                default:
                    $("#targetInputs").hide();
            }
        });

        // 连接WebSocket
        $("#btnConnect").on("click", function () {
            const url = $.trim($("#txtUrl").val());
            if (url.length <= 0) {
                alert("请输入WebSocket服务器地址!");
                return;
            }

            try {
                ws = new WebSocket(url);

                // ws connection succeeded
                ws.onopen = function () {
                    showInfo("WebSocket Server [" + url + "] Connection Succeeded!");
                    toggleControls(true);
                    // 连接成功后启动心跳机制
                    startPing();
                };

                // ws connection closed
                ws.onclose = function () {
                    // 清除心跳定时器
                    stopPing();
                    ws = null;
                    clientId = null;
                    toggleControls(false);
                    showError("WebSocket Server [" + url + "] Connection Closed!");
                };

                // ws connection error
                ws.onerror = function () {
                    // 清除心跳定时器
                    stopPing();
                    ws = null;
                    clientId = null;
                    toggleControls(false);
                    showError("WebSocket Server [" + url + "] Connection Error!");
                };

                // ws response message.
                ws.onmessage = function (result) {
                    try {
                        const data = JSON.parse(result.data);
                        handleServerMessage(data);
                    } catch (e) {
                        showWaring(" > " + result.data);
                    }
                };
            } catch (e) {
                showError("连接异常: " + e.message);
            }
        });

        // 断开WebSocket连接
        $("#btnDisconnect").on("click", function () {
            if (ws) {
                ws.close();
                ws = null;
            }
            stopPing();
            toggleControls(false);
            showInfo("已断开WebSocket连接");
        });


// 处理服务器消息
function handleServerMessage(data) {
    // 根据后端结构，字段是 Event 和 Data
    switch(data.e) {
        case "connected":
            clientId = data.Data.ID;
            showSuccess("连接成功，客户端ID: " + clientId);
            break;
        case "login":
            if (data.Data.status === "success") {
                showSuccess("登录成功，用户ID: " + data.Data.userId);
            } else {
                showError("登录失败: " + JSON.stringify(data.Data));
            }
            break;
        case "join":
            showInfo("加入房间成功，当前房间: " + JSON.stringify(data.Data));
            break;
        case "quit":
            showInfo("退出房间成功，当前房间: " + JSON.stringify(data.Data));
            break;
        case "ping":
            showInfo("收到服务器心跳响应");
            break;
        case "message":
            // 处理普通广播消息
            if (typeof data.Data === 'object' && data.Data.content) {
                showWaring("广播消息: " + data.Data.content);
            } else {
                showWaring("广播消息: " + JSON.stringify(data.Data));
            }
            break;
        case "private_message":
            showSuccess("私聊消息 [" + data.Data.fromUserId + "]: " + data.Data.content);
            break;
        case "room_message":
            showInfo("房间消息 [" + data.Data.roomName + "] [" + data.Data.fromUserId + "]: " + data.Data.content);
            break;
        case "broadcast_message":
            showWaring("广播消息 [" + data.Data.fromUserId + "]: " + data.Data.content);
            break;
        case "client_message":
            showInfo("客户端消息 [" + data.Data.fromClientId + "]: " + data.Data.content);
            break;
        case "message_sent":
            showSuccess("消息已发送给用户: " + data.Data.targetUserId);
            break;
        case "room_message_sent":
            showSuccess("房间消息已发送到: " + data.Data.roomName);
            break;
        case "broadcast_sent":
            showSuccess("广播消息已发送");
            break;
        case "client_message_sent":
            showSuccess("消息已发送给客户端: " + data.Data.targetClientId);
            break;
        case "error":
            showError("错误: " + JSON.stringify(data.Data));
            break;
        default:
            showWaring("未知消息: " + JSON.stringify(data));
    }
}



        // 启动心跳机制
        function startPing() {
            // 清除可能存在的旧定时器
            if (pingInterval) {
                clearInterval(pingInterval);
            }
            // 每60秒发送一次ping心跳
            pingInterval = setInterval(function () {
                if (ws && ws.readyState === WebSocket.OPEN) {
                    // 发送ping消息
                    const pingMsg = JSON.stringify({
                        Event: "ping",
                        Data: {}
                    });
                    ws.send(pingMsg);
                    showInfo("Ping sent...");
                }
            }, 60000); // 60秒间隔
        }

        // 停止心跳机制
        function stopPing() {
            if (pingInterval) {
                clearInterval(pingInterval);
                pingInterval = null;
            }
        }

        // 用户登录
        $("#btnLogin").on("click", function () {
            if (!checkConnection()) return;

            const userId = $.trim($("#txtUserId").val());
            if (userId.length <= 0) {
                alert("请输入用户ID!");
                return;
            }

            const loginMsg = JSON.stringify({
                Event: "login",
                Data: {
                    userId: userId
                }
            });
            ws.send(loginMsg);
            showSuccess("发送登录请求...");
        });

        // 标记为App
        $("#btnIsApp").on("click", function () {
            if (!checkConnection()) return;

            const isAppMsg = JSON.stringify({
                Event: "is_app",
                Data: {}
            });
            ws.send(isAppMsg);
            showSuccess("标记为App客户端...");
        });

        // 加入房间
        $("#btnJoin").on("click", function () {
            if (!checkConnection()) return;

            const roomName = $.trim($("#txtRoom").val());
            if (roomName.length <= 0) {
                alert("请输入房间名称!");
                return;
            }
            const joinMsg = JSON.stringify({
                Event: "join",
                Data: {
                    name: roomName
                }
            });
            ws.send(joinMsg);
            showSuccess("请求加入房间: " + roomName);
        });

        // 退出房间
        $("#btnQuit").on("click", function () {
            if (!checkConnection()) return;

            const roomName = $.trim($("#txtRoom").val());
            if (roomName.length <= 0) {
                alert("请输入房间名称!");
                return;
            }
            const quitMsg = JSON.stringify({
                Event: "quit",
                Data: {
                    name: roomName
                }
            });
            ws.send(quitMsg);
            showSuccess("请求退出房间: " + roomName);
        });

        // 发送消息
        $("#btnSend").on("click", function () {
            if (!checkConnection()) return;

            const msgType = $("#msgType").val();
            const content = $.trim($("#txtContent").val());
            
            if (content.length <= 0) {
                alert("请输入消息内容!");
                return;
            }

            let message = null;

            switch(msgType) {
                case "message":
                    message = JSON.stringify({
                        Event: "message",
                        Data: {
                            content: content
                        }
                    });
                    break;
                case "private_message":
                    const targetUserId = $.trim($("#targetUserId").val());
                    if (targetUserId.length <= 0) {
                        alert("请输入目标用户ID!");
                        return;
                    }
                    message = JSON.stringify({
                        Event: "private_message",
                        Data: {
                            targetUserId: targetUserId,
                            content: content
                        }
                    });
                    break;
                case "room_message":
                    const targetRoom = $.trim($("#targetRoom").val());
                    if (targetRoom.length <= 0) {
                        alert("请输入目标房间名!");
                        return;
                    }
                    message = JSON.stringify({
                        Event: "room_message",
                        Data: {
                            roomName: targetRoom,
                            content: content
                        }
                    });
                    break;
                case "broadcast_message":
                    message = JSON.stringify({
                        Event: "broadcast_message",
                        Data: {
                            content: content
                        }
                    });
                    break;
                case "client_message":
                    const targetClientId = $.trim($("#targetClientId").val());
                    if (targetClientId.length <= 0) {
                        alert("请输入目标客户端ID!");
                        return;
                    }
                    message = JSON.stringify({
                        Event: "client_message",
                        Data: {
                            targetClientId: targetClientId,
                            content: content
                        }
                    });
                    break;
            }

            if (message) {
                ws.send(message);
                showSuccess("发送消息: " + content);
                $("#txtContent").val("");
            }
        });

        // enter to send message
        $("#txtContent").on("keydown", function (event) {
            if (event.keyCode === 13 && event.ctrlKey) {
                $("#btnSend").trigger("click");
                event.preventDefault();
            }
        });
    })
</script>